package com.hp.bon.sgw.threads;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.core.ChannelServer;
import com.hp.bon.sgw.core.route.RouteInfo;
import com.hp.bon.sgw.domain.Node;
import com.hp.bon.sgw.start.SpringContext;
import com.hp.bon.sgw.util.Comutils;

public class StateAnalysThread extends TaskThread
{
  private static StateAnalysThread _instance;
  public static final Logger LOG = LoggerFactory.getLogger(StateAnalysThread.class);
  ConcurrentHashMap<String, Stat4SCID> stat4SCIDMap = new ConcurrentHashMap<String, Stat4SCID>();

  public WarningTree warningTree = new WarningTree();
  private String msgRateInfo;
	public static StateAnalysThread getInstance() {
		if (_instance == null) {
			_instance = new StateAnalysThread();
		}
		return _instance;
	}

	/**
	 * 先执行父类的构造函数，再执行子类的构造函数
	 */
	public StateAnalysThread() {
		setName("Task-StateAnalys");
		setSleepTime(30 * 1000);
	}

  public void updateStat4SCIDMap(CallParam callParam)
  {
    Stat4SCID stat = (Stat4SCID)this.stat4SCIDMap.get(callParam.getServiceContextId());
    if (stat == null) {
      stat = new Stat4SCID(callParam.getServiceContextId());
      stat4SCIDMap.put(callParam.getServiceContextId(), stat);
    }
    if (callParam.getRetCode() == 0) {
      stat._counterSuccess += 1L;

      if (callParam.getRecvRespTime() != 0L) {
    	 //soap ack  - 
        stat._latencyTimeOutside += callParam.getRecvRespTime() - callParam.getSendReqTime();
      }
      if (callParam.getSendRespTime() != 0L) {
        stat._latencyTimeTotal += callParam.getSendRespTime() - callParam.getRecvReqTime();
      }
    }
    else if (callParam.getRetCode() == 11203) {
      stat._counterTimeout += 1L;
    } else {
      stat._counterOther += 1L;
    }
    stat.updateTime = callParam.getSendRespTime();
  }

  public void process()
  {
    checkSCIDStatus(this.runTime - this.lastrunTime);
    anylysWarning4BONException();
  }

  public void checkSCIDStatus(long deltMs)
  {
    int deltSuccess = 0;
    int deltTimeout = 0;
    int deltOther = 0;
    LOG.warn("stat4SCIDMap=+"+this.stat4SCIDMap.values().size());
    for (Stat4SCID stat4SCID : this.stat4SCIDMap.values()) {
      Leaf4SCID leaf4SCID = this.warningTree.getLeaf(stat4SCID._contextId);
      if (leaf4SCID == null) {
        leaf4SCID = new Leaf4SCID(stat4SCID._contextId);

        warningTree.addLeaf(leaf4SCID);
      }
      convertStat2Leaf(stat4SCID, leaf4SCID);

      deltSuccess = (int)(deltSuccess + leaf4SCID._counterSuccess);
      deltTimeout = (int)(deltTimeout + leaf4SCID._counterTimeout);
      deltOther = (int)(deltOther + leaf4SCID._counterOther);

      adjustRouteByDeltRequest(leaf4SCID);
    }
    int total = deltSuccess + deltTimeout + deltOther;
    double rate = total * 1000.0D / deltMs;
    StringBuilder sb = new StringBuilder();
    sb.append("MsgRate=").append(String.format("%.2f", new Object[] { Double.valueOf(rate) }));
    sb.append(",deltMs=").append(deltMs);
    sb.append(",Success=").append(deltSuccess);
    sb.append(",Timeout=").append(deltTimeout);
    sb.append(",Other=").append(deltOther);
  //  Constants.LOG.info(sb.toString());
 //   this.msgRateInfo = (Comutils.formatTime(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss.SSS") + "|" + sb.toString());
  }

  public String getMsgRateInfo() {
    return this.msgRateInfo;
  }

  private void convertStat2Leaf(Stat4SCID stat4SCID, Leaf4SCID leaf4SCID)
  {
    leaf4SCID._counterSuccess = (stat4SCID._counterSuccess - leaf4SCID._counterSuccessLast);
    leaf4SCID._counterSuccessLast = stat4SCID._counterSuccess;
    leaf4SCID._counterTimeout = (stat4SCID._counterTimeout - leaf4SCID._counterTimeoutLast);
    leaf4SCID._counterTimeoutLast = stat4SCID._counterTimeout;
    leaf4SCID._counterOther = (stat4SCID._counterOther - leaf4SCID._counterOtherLast);
    leaf4SCID._counterOtherLast = stat4SCID._counterOther;

    leaf4SCID.calcStatus();

    if (leaf4SCID.curStatus == Constants.CheckStatus.OK) {
      long outTimeIncrease = stat4SCID._latencyTimeOutside - leaf4SCID._latencyTimeOutsideLast;
      leaf4SCID.averageTime4Outside = (outTimeIncrease / leaf4SCID._counterSuccess);
      long inTimeIncrease = stat4SCID._latencyTimeTotal - leaf4SCID._latencyTimeTotalLast - outTimeIncrease;
      leaf4SCID.averageTime4Inside = (inTimeIncrease / leaf4SCID._counterSuccess);
      
    }
    else {
      leaf4SCID.averageTime4Outside = 0L;
      leaf4SCID.averageTime4Inside = 0L;
    }
    leaf4SCID._latencyTimeOutsideLast = stat4SCID._latencyTimeOutside;
    leaf4SCID._latencyTimeTotalLast = stat4SCID._latencyTimeTotal;
  }

  private void adjustRouteByDeltRequest(Leaf4SCID leaf4SCID)
  {
    //RouteInfo arrayList = (RouteInfo)ChannelServer.routeMap.get(leaf4SCID.name);
	//"`"+leaf4SCID.name 这样写的是为了屏蔽检验拥赛这个功能
	RouteInfo arrayList = (RouteInfo)ChannelServer.routeMap.get("`"+leaf4SCID.name);
    if (arrayList != null) {
      double rejectPercent = 0.0D;
      int total = (int)(leaf4SCID._counterTimeout + leaf4SCID._counterSuccess);
      if (total > 2) {
        double warn = SpringContext.getInstance().getConfigService().getIntValue("business.fluxctrl.latency_warn", 50) * 1.0D / 100.0D;
        rejectPercent = leaf4SCID._counterTimeout * 1.0D / total - warn;
      }
      int t1 = 1000 * SpringContext.getInstance().getConfigService().getIntValue("business.fluxctrl.latency_t1", 20);
      int t2 = 1000 * SpringContext.getInstance().getConfigService().getIntValue("business.fluxctrl.latency_t2", 30);
      if (leaf4SCID.averageTime4Outside > t1) {
        double rejectPercent4Latency = leaf4SCID.averageTime4Outside - t1 * 1.0D / t2 - t1;
        if (rejectPercent4Latency > rejectPercent) {
          rejectPercent = rejectPercent4Latency;
        }
        Constants.LOG.warn(leaf4SCID.name + " average latency time:" + leaf4SCID.averageTime4Outside + " , rejectPercent:" + rejectPercent);
      }
      arrayList.rejectPercent4SCID = rejectPercent;
      LOG.warn("rejectPercent4SCID=+"+rejectPercent);
    }
  }

  public void anylysWarning4BONException()
  {
    long begin = System.currentTimeMillis();
    this.warningTree.calcStatus();
    ArrayList<String> warningList = new ArrayList<String>();
    this.warningTree.collectWaring(warningList, begin);
  }

  class Stat4Node
  {
    public Node node;
    public long _totalRecvMsgNum;
    public long _totalSentMsgNum;
    public long _totalRecvMsgSize;
    public long _totalSentMsgSize;
    public long _maxRecvMsgSize;
    public long _maxSentMsgSize;
    public long updateTime;

    Stat4Node()
    {
    }
  }

  public class Stat4SCID
  {
    public String _contextId;
    public long _counterSuccess;
    public long _counterTimeout;
    public long _counterOther;
    public long _latencyTimeTotal;
    public long _latencyTimeOutside;
    public long _totalRecvMsgSize;
    public long _totalSentMsgSize;
    public long updateTime;

    public Stat4SCID(String serviceContextId)
    {
      this._contextId = serviceContextId;
    }
  }
}
